package org.lc.cmd.util;

import lombok.Setter;
import org.lc.cmd.Cmd;
import org.lc.cmd.CmdContext;
import org.lc.cmd.CmdSession;
import org.lc.cmd.connect.CmdContextManager;
import org.lc.cmd.connect.CmdServerConfig;
import org.lc.cmd.connect.ServerSession;
import org.lc.cmd.exp.DevException;
import org.lc.cmd.model.StyledString;

import java.util.List;
import java.util.Optional;
import java.util.function.BiConsumer;

@Setter
public class CmdOutUtil {
    private static final String NULL_VALUE = "null";

    private static int cmdNameColor = 0x0000FF; // 蓝色

    private static int errorColor = 0xFF0000; // 红色

    private static int successColor = 0x00FF00; // 绿色

    private static int ipColor = 0x0000FF; // 蓝色

    private static int trueColor = 0x00FF00; // 绿色

    private static int falseColor = 0xFF0000; // 红色

    private static int tipColor = 0x808080; // 灰色

    private static int warnColor = 0xFFA500; // 橙色

    private static final Lazy<CmdContextManager> CONTEXT_MANAGER = new Lazy<>(() ->
            CmdServerConfig.defaultProvider.contextSupplier().get().getBean(CmdContextManager.class));

    // 各类样式输出，可set对应的颜色值来修改样式
    public static void writeTitle(String str, boolean above) {
        writeRgb(str, cmdNameColor, above);
    }

    @SuppressWarnings("unused")
    public static void writeWarn(String str, boolean above) {
        writeRgb(str, warnColor, above);
    }

    @SuppressWarnings("unused")
    public static void writeCmdName(String str, boolean above) {
        writeRgb(str, cmdNameColor, above);
    }

    public static void writeError(String str, boolean above) {
        writeRgb(str, errorColor, above);
    }

    @SuppressWarnings("unused")
    public static void writeSuccess(String str, boolean above) {
        writeRgb(str, successColor, above);
    }

    @SuppressWarnings("unused")
    public static void writeIp(String str, boolean above) {
        writeRgb(str, ipColor, above);
    }

    @SuppressWarnings("unused")
    public static void writeBoolean(boolean value, boolean above) {
        int color = value ? trueColor : falseColor;
        writeRgb("true", color, above);
    }

    @SuppressWarnings("unused")
    public static void writeTip(String str, boolean above) {
        writeRgb(str, tipColor, above);
    }

    public static void write(String str, boolean above) {
        write(new StyledString(str), above);
    }

    @SuppressWarnings("unused")
    public static void write(String str, int r, int g, int b, boolean above) {
        writeRgb(str, r << 16 | g << 8 | b, above);
    }

    public static void writeRgb(String str, int rgb, boolean above) {
        write(new StyledString(str, rgb), above);
    }

    public static void write(StyledString str, boolean above) {
        CmdContext context = CONTEXT_MANAGER.get().getCurrentContext();
        if (context != null) {
            if (above) {
                CmdSession session = context.request().getSession();
                if (session instanceof ServerSession) {
                    ((ServerSession) session).notify(str);
                } else {
                    throw new DevException("can not write str to this session: " + session.getClass());
                }
            } else {
                context.response().write(str);
            }
        } else {
            Cmd.INSTANCE.getBridge().write(str.toJlineString(), above);
        }
    }

    public static void writeln(boolean above) {
        write("\n", above);
    }

    public static void writeln() {
        writeln(false);
    }

    private static void writeSpace(int count) {
        for (int i = 0; i < count; i++) {
            write(" ", false);
        }
    }

    @SuppressWarnings("unused")
    public static void writeTable(List<CharSequence> head, List<List<CharSequence>> body, boolean lineNumber) {
        writeTable(head, body, (str, width) -> {
            if (str instanceof StyledString) {
                CmdOutUtil.write((StyledString) str, false);
            } else {
                CmdOutUtil.writeTitle(str.toString(), false);
            }
            writeSpace(width - str.length() + 1);
        }, (str, width) -> {
            if (str instanceof StyledString) {
                CmdOutUtil.write((StyledString) str, false);
            } else {
                CmdOutUtil.write(str.toString(), false);
            }
            writeSpace(width - str.length() + 1);
        }, lineNumber);
    }

    public static void writeTable(List<CharSequence> head, List<List<CharSequence>> body, BiConsumer<CharSequence,
            Integer> headWriter,
            BiConsumer<CharSequence, Integer> bodyWriter, boolean lineNumber) {
        int[] width = new int[head.size()];
        int lineNumberWidth = Math.max(String.valueOf(body.size()).length(), 2);
        for (int i = 0; i < head.size(); i++) {
            width[i] = Optional.ofNullable(head.get(i)).orElse(NULL_VALUE).length();
        }
        for (List<CharSequence> line : body) {
            if (line.size() != width.length) {
                throw new IllegalArgumentException("table列数不对应");
            }
            for (int i = 0; i < line.size(); i++) {
                int length = Optional.ofNullable(line.get(i)).orElse(NULL_VALUE).length();
                if (length > width[i]) {
                    width[i] = length;
                }
            }
        }
        if (lineNumber) {
            headWriter.accept("行号", lineNumberWidth);
        }
        for (int i = 0; i < head.size(); i++) {
            headWriter.accept(head.get(i), width[i]);
        }
        writeln();
        for (int num = 1; num <= body.size(); num++) {
            List<CharSequence> line = body.get(num);
            if (lineNumber) {
                bodyWriter.accept(String.valueOf(num), lineNumberWidth);
            }
            for (int i = 0; i < line.size(); i++) {
                bodyWriter.accept(line.get(i), width[i]);
            }
            writeln();
        }
    }
}